using System;
using System.Collections.Generic;
using System.Text;
using AgilePlannerDT.Data;
using System.Windows.Media;
using AgilePlannerDT.Utils;
using System.Xml.Schema;
using System.Xml;

namespace AgilePlannerDT.Data.Impl
{
    public class StoryCardDataObject : IndexCardDataObject, StoryCard
    {
        #region Constants

        public static readonly int FRONT_SIDE = 0;
        public static readonly int RICH_TEST_SIDE = 1;
        public static readonly int PLAIN_TEST_SIDE = 2;
        public static readonly int PROTOTYPE_SIDE = 3;
        public static readonly int HANDWRITING_SIDE = 4;

        public static readonly string CARD_OWNER_PROPERTY = "CardOwner";
        public static readonly string BACKGROUND_PROPERTY = "Background";
        public static readonly string ACCEPTANCE_TEST_URL_PROPERTY = "AcceptanceTestUrl";
        public static readonly string ACCEPTANCE_TEST_TEXT_PROPERTY = "AcceptanceTestText";
        public static readonly string CURRENT_SIDE_UP_PROPERTY = "CurrentSideUp";
        public static readonly string HANDWRITING_IMAGE_PROPERTY = "HandwritingImage";
        public static readonly string FIT_ID = "0";
        public static readonly string RALLY_ID = "0";

        #endregion

        #region Attributes

        protected string acceptanceTestText, acceptanceTestUrl, cardOwner, rallyID, fitID;
        protected int currentSideUp = FRONT_SIDE;
        protected byte[] handWritingImage;
        protected Color background;

        #endregion

        #region Constructors

        public StoryCardDataObject()
            : this(0, 0, CardConstants.STORYCARD_DEFAULT_NAME, CardConstants.STORYCARD_DEFAULT_DESCRIPTION,
            CardConstants.STORYCARD_DEFAULT_WIDTH, CardConstants.STORYCARD_DEFAULT_HEIGHT, CardConstants.INDEXCARD_DEFAULT_LOCATION_X, CardConstants.INDEXCARD_DEFAULT_LOCATION_Y,
            0f, 0f, 0f, 0f, CardConstants.STATUS_DEFINED, Colors.White, CardConstants.STORYCARD_DEFAULT_OWNER, 0f, new byte[0],RALLY_ID,FIT_ID)
        {
        }
 

        public StoryCardDataObject(StoryCard original)
        {
            this.acceptanceTestText = original.AcceptanceTestText;
            this.acceptanceTestUrl = original.AcceptanceTestUrl;
            this.actualEffort = original.ActualEffort;
            this.background = original.Background;
            this.bestCaseEstimate = original.BestCaseEstimate;
            this.cardOwner = original.CardOwner;
            this.currentSideUp = original.CurrentSideUp;
            this.description = original.Description;

            //not sure if shallow copy with .Clone() is enough here
            this.handWritingImage = new byte[original.HandwritingImage.Length];
            original.HandwritingImage.CopyTo(this.handWritingImage, 0);

            this.height = original.Height;
            this.id = original.ID;
            this.SyncID = original.SyncID;
            this.locationX = original.LocationX;
            this.locationY = original.LocationY;
            this.mostLikelyEstimate = original.MostlikelyEstimate;
            this.name = original.Name;
            this.parent = original.Parent;
            this.rotationAngle = original.RotationAngle;
            this.status = original.Status;
            this.width = original.Width;
            this.worstCaseEstimate = original.WorstCaseEstimate;
            this.rallyID = original.RallyID;
            this.fitID = original.FitID;
        }

        public StoryCardDataObject(long parentid, string name, string description,
            double width, double height, double locationX, double locationY,
            float bestCaseEstimate, float mostlikelyEstimate, float worstCaseEstimate, float actualEffort,
            string status, Color cardColor, string cardOwner, float rotationAngle)
            : this(0, parentid, name, description,
                width, height, locationX, locationY,
                bestCaseEstimate, mostlikelyEstimate, worstCaseEstimate, actualEffort,
                status, cardColor, cardOwner, rotationAngle, new byte[0],RALLY_ID,FIT_ID)
        {
        }

        public StoryCardDataObject(long cardID, long parentid, string name, string description,
            double width, double height, double locationX, double locationY,
            float bestCaseEstimate, float mostlikelyEstimate, float worstCaseEstimate, float actualEffort,
            string status, Color cardColor, string cardOwner, float rotationAngle, byte[] handWritingImage,string rallyID, string fitID)
        {
            //better have an empty string than null
            this.acceptanceTestText = "";
            this.acceptanceTestUrl = "";

            this.actualEffort = actualEffort;
            this.background = cardColor;
            this.bestCaseEstimate = bestCaseEstimate;
            this.cardOwner = cardOwner;
            this.description = description;
            this.handWritingImage = handWritingImage;
            this.height = height;
            this.id = cardID;
            this.locationX = locationX;
            this.locationY = locationY;
            this.mostLikelyEstimate = mostlikelyEstimate;
            this.name = name;
            this.parent = parentid;
            this.rotationAngle = rotationAngle;
            this.status = status;
            this.width = width;
            this.worstCaseEstimate = worstCaseEstimate;
            this.rallyID = rallyID;
            this.fitID = fitID;
        }
        


        #endregion

        #region StoryCard Members

        public string AcceptanceTestText
        {
            get { return this.acceptanceTestText; }
            set
            {
                if (this.acceptanceTestText == value)
                {
                    return;
                }
                object before = Clone();
                this.acceptanceTestText = value;
                object after = Clone();
                Notify(ACCEPTANCE_TEST_TEXT_PROPERTY, before, after);
                //Notify(ACCEPTANCE_TEST_TEXT_PROPERTY);
            }
        }

        public string AcceptanceTestUrl
        {
            get { return this.acceptanceTestUrl; }
            set
            {
                if (this.acceptanceTestUrl == value)
                {
                    return;
                }
                object before = Clone();
                this.acceptanceTestUrl = value;
                object after = Clone();
                Notify(ACCEPTANCE_TEST_URL_PROPERTY, before, after);
                //Notify(ACCEPTANCE_TEST_URL_PROPERTY);
            }
        }

        public Color Background
        {
            get { return this.background; }
            set
            {
                if (this.background.Equals(value))
                {
                    return;
                }
                object before = Clone();
                this.background = value;
                object after = Clone();
                Notify(BACKGROUND_PROPERTY, before, after);
                //Notify(BACKGROUND_PROPERTY);
            }
        }

        public string CardOwner
        {
            get { return this.cardOwner; }
            set
            {
                if (this.cardOwner == value)
                {
                    return;
                }
                object before = Clone();
                this.cardOwner = value;
                object after = Clone();
                Notify(CARD_OWNER_PROPERTY, before, after);
                //Notify(CARD_OWNER_PROPERTY);
            }
        }

        public int CurrentSideUp
        {
            get { return this.currentSideUp; }
            set
            {
                if (this.currentSideUp == value)
                {
                    return;
                }
                object before = Clone();
                this.currentSideUp = value;
                object after = Clone();
                Notify(CURRENT_SIDE_UP_PROPERTY, before, after);
                //Notify(CURRENT_SIDE_UP_PROPERTY);
            }
        }

        public byte[] HandwritingImage
        {
            get { return this.handWritingImage; }
            set
            {
                if (this.handWritingImage.Equals(value))
                {
                    return;
                }
                object before = Clone();
                this.handWritingImage = value;
                object after = Clone();
                Notify(HANDWRITING_IMAGE_PROPERTY, before, after);
                //Notify(HANDWRITING_IMAGE_PROPERTY);
            }
        }

        public new float RemainingEffort
        {
            get { return mostLikelyEstimate - actualEffort; }
        }

        public string RallyID
        {
            get { return this.rallyID; }
            set
            {
                this.rallyID = value;
            }
        }
        public string FitID
        {
            get
            {
                return this.fitID;
            }
            set
            {
                this.fitID = value;
            }
        }

        public void Update(StoryCard storycard)
        {
            this.acceptanceTestText = storycard.AcceptanceTestText;
            this.acceptanceTestUrl = storycard.AcceptanceTestUrl;
            this.actualEffort = storycard.ActualEffort;
            this.background = storycard.Background;
            this.bestCaseEstimate = storycard.BestCaseEstimate;
            this.cardOwner = storycard.CardOwner;
            this.currentSideUp = storycard.CurrentSideUp;
            this.description = storycard.Description;
            this.handWritingImage = storycard.HandwritingImage;
            this.height = storycard.Height;
            this.locationX = storycard.LocationX;
            this.locationY = storycard.LocationY;
            this.mostLikelyEstimate = storycard.MostlikelyEstimate;
            this.name = storycard.Name;
            this.rotationAngle = storycard.RotationAngle;
            this.status = storycard.Status;
            this.width = storycard.Width;
            this.worstCaseEstimate = storycard.WorstCaseEstimate;
            this.rallyID = storycard.RallyID;
            this.fitID = storycard.FitID;
        }

        #endregion

        #region Object Members

        public override string ToString()
        {
            return "StoryCard={" +
                "ID["+ID.ToString()+"] "+
                "SyncID[" + SyncID.ToString() + "] " +
                "Title[" + Name.ToString() + "] " +
            "}";
        }

        public override bool Equals(object o)
        {
            if (o is StoryCardDataObject)
            {
                StoryCardDataObject sc = (StoryCardDataObject)o;

                byte[] hwi1 = HandwritingImage;
                byte[] hwi2 = sc.HandwritingImage;

                bool handwritingsEqual = true;

                if (hwi1.Length != hwi2.Length)
                    return false;
                else
                {
                    for (int i = 0; i < hwi1.Length; i++)
                    {
                        handwritingsEqual = handwritingsEqual && (hwi1[i] == hwi2[i]);
                    }
                }

                return (sc.AcceptanceTestText.Equals(AcceptanceTestText) &&
                    sc.AcceptanceTestUrl.Equals(AcceptanceTestUrl) &&
                    (sc.ActualEffort == ActualEffort) &&
                    sc.Background.Equals(Background) &&
                    (sc.BestCaseEstimate == BestCaseEstimate) &&
                    sc.CardOwner.Equals(CardOwner) &&
                    (sc.CurrentSideUp == CurrentSideUp) &&
                    sc.Description.Equals(Description) &&
                    handwritingsEqual &&
                    (sc.Height == Height) &&
                    (sc.ID == ID) &&
                    (sc.LocationX == LocationX) &&
                    (sc.LocationY == LocationY) &&
                    (sc.MostlikelyEstimate == MostlikelyEstimate) &&
                    sc.Name.Equals(Name) &&
                    (sc.Parent == Parent) &&
                    ((int)sc.RotationAngle == (int)RotationAngle) &&
                    sc.Status.Equals(Status) &&
                    (sc.Width == Width) &&
                    (sc.WorstCaseEstimate == WorstCaseEstimate));
                //return ((StoryCardDataObject)o).ID == this.ID;

            }
            return false;
        }

        public override int GetHashCode()
        {
            return (int)ID;
        }

        #endregion

        #region IXmlSerializable Members

        public XmlSchema GetSchema()
        {
            return null;
        }

        public void ReadXml(XmlReader reader)
        {
            AcceptanceTestText = reader.GetAttribute("TestText");
            AcceptanceTestUrl = reader.GetAttribute("TestURL");
            ActualEffort = float.Parse(reader.GetAttribute("Actual"));
            Background = (Color)new CardColorConverter().ConvertFrom(reader.GetAttribute("Color"));
            BestCaseEstimate = float.Parse(reader.GetAttribute("BestCase"));
            CardOwner = reader.GetAttribute("CardOwner");
            CurrentSideUp = int.Parse(reader.GetAttribute("CurrentSideUp"));
            Description = reader.GetAttribute("Description");
            Height = double.Parse(reader.GetAttribute("Height"));
            ID = long.Parse(reader.GetAttribute("ID"));
            SyncID = int.Parse(reader.GetAttribute("SyncID"));
            LocationX = double.Parse(reader.GetAttribute("XLocation"));
            LocationY = double.Parse(reader.GetAttribute("YLocation"));
            MostlikelyEstimate = float.Parse(reader.GetAttribute("MostLikely"));
            Name = reader.GetAttribute("Name");
            Parent = long.Parse(reader.GetAttribute("Parent"));
            RotationAngle = double.Parse(reader.GetAttribute("RotationAngle"));
            Status = reader.GetAttribute("Status");
            Width = double.Parse(reader.GetAttribute("Width"));
            WorstCaseEstimate = float.Parse(reader.GetAttribute("WorstCase"));
            RallyID = reader.GetAttribute("RallyID");
            FitID = reader.GetAttribute("FitID");
        }

        public void WriteXml(XmlWriter writer)
        {
            writer.WriteStartElement("StoryCard");
            writer.WriteAttributeString("TestText", this.AcceptanceTestText);
            writer.WriteAttributeString("TestURL", this.AcceptanceTestUrl);
            writer.WriteAttributeString("Actual", ((float)this.ActualEffort).ToString());
            writer.WriteAttributeString("Color", (string)new CardColorConverter().ConvertTo(Background, typeof(string)));
            writer.WriteAttributeString("BestCase", ((float)this.BestCaseEstimate).ToString());
            writer.WriteAttributeString("CardOwner", this.CardOwner);
            writer.WriteAttributeString("CurrentSideUp", this.CurrentSideUp.ToString());
            writer.WriteAttributeString("Description", this.Description);
            writer.WriteAttributeString("Height", ((int)this.Height).ToString());
            writer.WriteAttributeString("ID", this.ID.ToString());
            writer.WriteAttributeString("SyncID", this.SyncID.ToString());
            writer.WriteAttributeString("XLocation", ((int)this.LocationX).ToString());
            writer.WriteAttributeString("YLocation", ((int)this.LocationY).ToString());
            writer.WriteAttributeString("MostLikely", ((float)this.MostlikelyEstimate).ToString());
            writer.WriteAttributeString("Name", this.Name);
            writer.WriteAttributeString("Parent", this.Parent.ToString());
            writer.WriteAttributeString("RotationAngle", ((float)this.RotationAngle).ToString());
            writer.WriteAttributeString("Status", this.Status);
            writer.WriteAttributeString("Width", ((int)this.Width).ToString());
            writer.WriteAttributeString("WorstCase", ((float)this.WorstCaseEstimate).ToString());
            writer.WriteAttributeString("RallyID", this.rallyID.ToString());
            writer.WriteAttributeString("FitID", this.fitID.ToString());
            writer.WriteEndElement();
        }

        #endregion

        #region ICloneable Members

        public override object Clone()
        {
            return new StoryCardDataObject(this);
        }

        #endregion
    }
}